// Promise的三种状态 pending fulfilled rejected

class MyPromise {

  constructor(executor) {
    this.initValue(); // 初始化值
    this.initBind(); // 初始化this指向

    try {
      executor(this.resolve, this.reject); // 执行传入的函数
    } catch (error) {
      this.reject(error);
    }
  }

  initBind() {
    this.resolve = this.resolve.bind(this);
    this.reject = this.reject.bind(this);
  }

  initValue() {
    // 初始化
    this.promiseResult = null; // 终值
    this.promiseState = 'pending'; // 状态
    this.onFulfilledCallbacks = []; // 保存成功回调
    this.onRejectedCallbacks = []; // 保存失败回调
  }

  resolve(value) {
    if (this.promiseState !== 'pending') return;
    this.promiseState = 'fulfilled';
    this.promiseResult = value;

    // 执行保存的成功回调
    while (this.onFulfilledCallbacks.length) {
      this.onFulfilledCallbacks.shift()(this.promiseResult);
    }
  }

  reject(reason) {
    if (this.promiseState !== 'pending') return;
    this.promiseState = 'rejected';
    this.promiseResult = reason;

    // 执行保存的失败回调
    while (this.onRejectedCallbacks.length) {
      this.onRejectedCallbacks.shift()(this.promiseResult);
    }
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : val => val;
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };

    if (this.promiseState === 'fulfilled') {
      onFulfilled(this.promiseResult);
    } else if (this.promiseState === 'rejected') {
      onRejected(this.promiseResult);
    } else if (this.promiseState === 'pending') {
      // 如果状态为pending，则暂时保存两个回调
      this.onFulfilledCallbacks.push(onFulfilled.bind(this));
      this.onRejectedCallbacks.push(onRejected.bind(this));
    }
  }
}


const p1 = new MyPromise((resolve, reject) => {
  // resolve('success');
  // reject('failed');
  throw ('error');
});

p1.then(res => console.log(res), err => console.log(err))


const p2 = new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve('success');
  }, 3000);
});

p2.then(res => console.log(res), err => console.log(err));
